package yiwise

import (
	"crypto/sha256"
	"encoding/hex"
	"encoding/json"
	"fmt"
	"i-hea/utils/httplib"
	"i-hea/utils/typeSwitch"
	"net/url"
	"strconv"
	"strings"
	"time"

	log "github.com/astaxie/beego/logs"
	"github.com/pkg/errors"
)

const (
	TanyiApiUrl = "https://openapi.tanyibot.com"
)

func NewClient(appKey, appSecret, tenantSig, apiBaseUrl, version string) *ApiClient {
	client := &ApiClient{
		appKey:     appKey,
		appSecret:  appSecret,
		apiBaseUrl: apiBaseUrl,
		version:    version,
		tenantSig:  tenantSig,
		httpClient: httplib.NewHttpClient(),
	}
	return client
}

func (c *ApiClient) Headers() (headers map[string]string) {
	headers = make(map[string]string)
	timestamp := time.Now().UnixNano() / int64(time.Millisecond)
	timestampStr := strconv.FormatInt(timestamp, 10)
	headers["timestamp"] = timestampStr
	headers["appKey"] = c.appKey
	headers["appSecret"] = c.appSecret
	headers["tenantSign"] = c.tenantSig
	headers["version"] = c.version
	signature := c.sign(timestampStr)
	headers["signature"] = signature
	return headers
}

func (c *ApiClient) sign(timestamp string) string {
	secret := strings.Join([]string{"appKey=", c.appKey, "&appSecret=", c.appSecret, "&tenantSign=", c.tenantSig, "&version=", c.version, "&timestamp=", timestamp}, "")
	key := []byte(c.tenantSig)
	h := sha256.New()
	h.Write(key)
	h.Write([]byte(secret))
	b := h.Sum(nil)
	sign := hex.EncodeToString(b)
	return sign
}

// 机器人初始化
func (c *ApiClient) InitRobot(dialogFlowId, robotCount int) (*Return, error) {
	result := new(Return)

	param := InitRobotParam{
		DialogFlowId: dialogFlowId,
		RobotCount:   robotCount,
	}
	jsonReq, _ := json.Marshal(param)
	resbody, err := c.httpClient.PostWithHeader(c.GetApiUrl("/yunliu/createJob", nil), c.Headers(), jsonReq)
	if nil != err {
		return result, errors.Errorf("post return failed: %v", err)
	}
	log.Debug(string(resbody))
	_ = json.Unmarshal(resbody, &result)
	return result, nil
}

// 机器人注销/ 销毁
func (c *ApiClient) DestroyRobot(dialogFlowId int) (*Return, error) {
	result := new(Return)
	param := DialogFlowParam{
		DialogFlowId: dialogFlowId,
	}
	jsonReq, _ := json.Marshal(param)

	resbody, err := c.httpClient.PostWithHeader(c.GetApiUrl("/yunliu/stopJob", nil), c.Headers(), jsonReq)
	if nil != err {
		return result, errors.Errorf("post return failed %v", err)
	}

	log.Debug(string(resbody))
	_ = json.Unmarshal(resbody, &result)
	return result, nil
}

func (c *ApiClient) GetTenant() (*Return, error) {
	result := &Return{}
	// TODO 修改链接
	resbody, err := c.httpClient.GetWithHeader(c.GetApiUrl("/tenant/getTenant", nil), c.Headers())
	if nil != err {
		log.Debug("destroy Robot failed", err)
		return result, errors.Errorf("post return failed %v", err)
	}
	log.Debug(string(resbody))
	_ = json.Unmarshal(resbody, &result)
	return result, nil
}

func (c *ApiClient) DialogFlowPage(dialogFlowPageParam DialogFlowPageParam) (*DialogFlowReturn, error) {
	result := &DialogFlowReturn{}
	jsonReq, _ := json.Marshal(dialogFlowPageParam)
	resbody, err := c.httpClient.PostWithHeader(c.GetApiUrl("/dialogFlow/getTotalDialogFlowList", nil), c.Headers(), jsonReq)
	if nil != err {
		log.Debug("destroy Robot failed", err)
		return result, errors.Errorf("post return failed %v", err)
	}
	log.Debug(string(resbody))
	_ = json.Unmarshal(resbody, &result)
	return result, nil
}
func (c *ApiClient) DialogFlowDetail(dialogFlow DialogFlowParam) (*DialogFlowDetailReturn, error) {
	var result DialogFlowDetailReturn
	resbody, err := c.httpClient.GetWithHeader(c.GetApiUrl("/dialogFlow/getDialogContentInfo", dialogFlow), c.Headers())
	if nil != err {
		log.Debug("dialog detail  failed", err)
		return &result, errors.Errorf("post return failed %v", err)
	}
	log.Debug(string(resbody))
	_ = json.Unmarshal(resbody, &result)
	return &result, nil
}

func (c *ApiClient) CopyDialogFlow(dialog CopyDialogFlowParam) (*DialogFlowCopyReturn, error) {
	result := &DialogFlowCopyReturn{}
	jsonReq, _ := json.Marshal(dialog)
	println(string(jsonReq))
	resbody, err := c.httpClient.PostWithHeader(c.GetApiUrl("/dialogFlow/copyDialogFlow", nil), c.Headers(), jsonReq)
	if nil != err {
		log.Debug("destroy Robot failed", err)
		return result, errors.Errorf("post return failed %v", err)
	}
	log.Debug(string(resbody))
	_ = json.Unmarshal(resbody, &result)
	return result, nil
}

func (c *ApiClient) UploadRecord(param UploadDialogFlowParam) (*Return, error) {
	uploadParam := make(map[string]string)
	uploadParam["dialogFlowId"] = param.DialogFlowId
	resbody, err := c.httpClient.UploadFile(c.GetApiUrl("/dialogFlow/batchUpload", nil), param.FileName(), param.FilePath, c.Headers(), uploadParam)
	if nil != err {
		log.Debug("upload record failed ", err)
		return nil, errors.Errorf("upload record failed %v", err)
	}
	log.Debug(string(resbody))
	var result Return
	_ = json.Unmarshal(resbody, &result)
	return &result, nil
}

func (c *ApiClient) GetApiUrl(reqUrl string, obj interface{}) string {
	urlBuilder := new(strings.Builder)
	urlBuilder.WriteString(c.apiBaseUrl)
	urlBuilder.WriteString("/apiOpen/")
	urlBuilder.WriteString(c.version)
	urlBuilder.WriteString(reqUrl)
	if obj != nil {
		params := typeSwitch.Struct2MapUrlParam(obj)
		urlParamBuilder := new(strings.Builder)
		urlParamBuilder.WriteString("?")
		for k, v := range params {
			urlParamBuilder.WriteString(k)
			urlParamBuilder.WriteString("=")
			urlParamBuilder.WriteString(url.QueryEscape(fmt.Sprintf("%v", v)))
		}
		if urlParamBuilder.Len() > 0 {

			urlBuilder.WriteString(urlParamBuilder.String())
		}

	}
	return urlBuilder.String()
}
